package faf.web.tests;

import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.persistence.EntityManager;

import junit.framework.Assert;

import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.web.servlet.ModelAndView;

import faf.business.QuestionManager;
import faf.business.SheetManager;
import faf.business.SurveyManager;
import faf.business.UserManager;
import faf.dao.JpaUtils;
import faf.entities.Account;
import faf.entities.Answer;
import faf.entities.Confidentiality;
import faf.entities.Properties;
import faf.entities.Question;
import faf.entities.QuestionType;
import faf.entities.Sheet;
import faf.entities.SheetState;
import faf.entities.Survey;
import faf.web.SheetController;
import faf.web.data.SheetForm;
import faf.web.data.SheetFormValidator;

public class SheetControllerTests {
	static JpaUtils jpautils;
	static UserManager userManager;
	static SheetManager sheetManager;
	static SurveyManager surveyManager;
	static QuestionManager questionManager;
	static SheetController sheetController;
	static Account simpleUser;
	static Account otherUser;
	static Sheet sheet;
	static Sheet unauthorizedSheet;

	@BeforeClass
	public static void beforeClass() throws Exception {
		injectBusinessLayer();

		simpleUser = createAccount("lastname", "firstname", "mail@mail.ml",
				"testouillage", false, false, new ArrayList<Sheet>(),
				new ArrayList<Survey>());

		otherUser = createAccount("lastname 2", "firstname 2", "mail2@mail.ml",
				"testouillage", false, false, new ArrayList<Sheet>(),
				new ArrayList<Survey>());

		// survey creation and affectation

		Survey survey = setSurvey("survey", "a test survey",
				Confidentiality.PUBLIC, true, simpleUser,
				new ArrayList<Question>(), new ArrayList<Sheet>());
		sheet = setSheet(survey, simpleUser, new ArrayList<Answer>(),
				SheetState.PENDING);

		Survey survey2 = setSurvey("survey 2", "a test survey",
				Confidentiality.PUBLIC, true, simpleUser,
				new ArrayList<Question>(), new ArrayList<Sheet>());
		unauthorizedSheet = setSheet(survey2, otherUser,
				new ArrayList<Answer>(), SheetState.PENDING);

		List<Question> questionList = new ArrayList<Question>();
		questionList.add(setQuestion("q1", new ArrayList<Properties>(), 1,
				false, QuestionType.STRING, new ArrayList<Answer>(), survey));
		questionList.add(setQuestion("q2", new ArrayList<Properties>(), 2,
				true, QuestionType.STRING, new ArrayList<Answer>(), survey));
		survey.setQuestionList(questionList);

		EntityManager em = jpautils.createEntityManger();
		em.getTransaction().begin();
		em.persist(survey);
		em.persist(sheet);
		em.persist(survey2);
		em.persist(unauthorizedSheet);
		for (Question question : questionList) {
			em.persist(question);
		}
		em.getTransaction().commit();
	}

	static public void injectBusinessLayer() throws Exception {
		HashMap<String, String> config = new HashMap<String, String>();
		config.put("hibernate.hbm2ddl.auto", "create-drop");
		jpautils = new JpaUtils(config);
		userManager = new UserManager();
		userManager.setJpautils(jpautils);
		sheetManager = new SheetManager();
		sheetManager.setJpautils(jpautils);
		surveyManager = new SurveyManager();
		surveyManager.setJpautils(jpautils);
		questionManager = new QuestionManager();
		questionManager.setJpautils(jpautils);
		sheetController = new SheetController();
		sheetController.setSheetManager(sheetManager);
		sheetController.setUserManager(userManager);
		sheetController.setSurveyManager(surveyManager);
	}

	static public Account createAccount(String lastname, String firstname,
			String mail, String password, boolean redactor,
			boolean administrator, List<Sheet> sheetList,
			List<Survey> surveyList) throws Exception {
		Account account = new Account();
		account.setFirstname(firstname);
		account.setLastname(lastname);
		account.setMail(mail);
		account.setPassword(password);
		account.setRedactor(redactor);
		account.setAdministrator(administrator);
		account.setSheetList(sheetList);
		account.setSurveyList(surveyList);
		account = userManager.createAccount(account);
		return account;
	}

	public static Survey setSurvey(String title, String description,
			Confidentiality confidentiality, boolean open, Account account,
			List<Question> questionList, List<Sheet> sheetList)
			throws Exception {
		Survey survey = new Survey();
		survey.setTitle(title);
		survey.setDescription(description);
		survey.setConfidentiality(confidentiality);
		survey.setOpen(open);
		survey.setAccount(account);
		survey.setQuestionList(questionList);
		survey.setSheetList(sheetList);
		return survey;
	}

	static public Sheet setSheet(Survey survey, Account account,
			List<Answer> answerList, SheetState state) throws Exception {
		Sheet sheet = new Sheet();
		sheet.setSurvey(survey);
		sheet.setAccount(account);
		sheet.setAnswerList(answerList);
		sheet.setState(state);
		return sheet;
	}

	static public Question setQuestion(String title,
			List<Properties> properties, int position, boolean obligatory,
			QuestionType type, List<Answer> answers, Survey survey) {
		Question question = new Question();
		question.setTitle(title);
		question.setProperties(properties);
		question.setPosition(position);
		question.setObligatory(obligatory);
		question.setType(type);
		question.setAnswer(answers);
		question.setSurvey(survey);
		return question;
	}

	public boolean validateForm(SheetForm form) {
		Errors errors = new BindException(form, "form");
		SheetFormValidator validator = new SheetFormValidator();
		validator.setSheetManager(sheetManager);
		validator.setSurveyManager(surveyManager);
		validator.validate(form, errors);
		System.out.println(errors);
		return !errors.hasErrors();
	}

	@After
	public void purge() {
		EntityManager em = jpautils.createEntityManger();
		em.getTransaction().begin();
		em.createQuery("DELETE FROM " + Answer.class.getName() + " e WHERE 1=1")
				.executeUpdate();
		em.getTransaction().commit();
		em.close();
	}

	@Test
	public void testLoggedUserAccessToAvailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("GET",
				"sheet.htm");

		request.getSession().setAttribute("user", simpleUser);
		request.setParameter("id", String.valueOf(sheet.getId()));

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView modelAndView = sheetController.handleRequest(request,
				response);

		assertNull(modelAndView.getViewName());
		assertNotNull(request.getAttribute("command"));
		assertNotNull(request.getAttribute("sheet"));
		assertNotNull(request.getAttribute("survey"));
		Sheet resultSheet = (Sheet) request.getAttribute("sheet");
		assertEquals(sheet.getId(), resultSheet.getId());
	}

	@Test
	public void testNonLoggedUserAccessToAvailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("GET",
				"sheet.htm");

		request.setParameter("id", String.valueOf(sheet.getId()));

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView modelAndView = sheetController.handleRequest(request,
				response);

		assertEquals(modelAndView.getViewName(), "login");
		assertNull(request.getAttribute("command"));
		assertNull(request.getAttribute("sheet"));
		assertNull(request.getAttribute("survey"));
	}

	@Test
	public void testLoggedUserAccessToUnavailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("GET",
				"sheet.htm");

		request.getSession().setAttribute("user", simpleUser);
		request.setParameter("id", String.valueOf(-1));

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView modelAndView = sheetController.handleRequest(request,
				response);

		assertNull(modelAndView.getViewName());
		assertNull(request.getAttribute("sheet"));
	}

	@Test
	public void testNonLoggedUserAccessToUnavailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("GET",
				"sheet.htm");

		request.setParameter("id", String.valueOf(-1));

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView modelAndView = sheetController.handleRequest(request,
				response);

		assertEquals(modelAndView.getViewName(), "login");
		assertNull(request.getAttribute("command"));
		assertNull(request.getAttribute("sheet"));
		assertNull(request.getAttribute("survey"));
	}

	@Test
	public void testLoggedUserAccessToUnauthorizedSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("GET",
				"sheet.htm");

		request.getSession().setAttribute("user", simpleUser);
		request.setParameter("id", String.valueOf(unauthorizedSheet.getId()));

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView modelAndView = sheetController.handleRequest(request,
				response);

		assertNull(modelAndView.getViewName());
		assertNull(request.getAttribute("sheet"));
	}

	@Test
	public void testLoggedUserSubmitOnAvailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("POST",
				"sheet.htm");

		request.getSession().setAttribute("user", simpleUser);
		request.setParameter("id", String.valueOf(sheet.getId()));

		request.setParameter("answers[1]", "r1");
		request.setParameter("answers[2]", "r2");

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView mav = sheetController.handleRequest(request, response);

		SheetForm form = (SheetForm) request.getAttribute("command");
		assertNotNull(form);
		for (String key : form.getAnswers().keySet()) {
			assertNotNull(form.getAnswers().get(key));
		}

		assertEquals(2, sheetManager.get(sheet.getId()).getAnswerList().size());
	}

	@Test
	public void testNonLoggedUserSubmitOnAvailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("POST",
				"sheet.htm");

		request.setParameter("id", String.valueOf(sheet.getId()));

		request.setParameter("answers[1]", "r1");
		request.setParameter("answers[2]", "r2");

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView modelAndView = sheetController.handleRequest(request,
				response);
		assertEquals("login", modelAndView.getViewName());
		SheetForm form = (SheetForm) request.getAttribute("command");
		assertNull(form);
		assertEquals(0, sheetManager.get(sheet.getId()).getAnswerList().size());
	}

	@Test
	public void testLoggedUserSubmitOnUnvailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("POST",
				"sheet.htm");

		request.getSession().setAttribute("user", simpleUser);
		request.setParameter("id", String.valueOf(unauthorizedSheet.getId()));
		request.setParameter("answers[1]", "r1");
		request.setParameter("answers[2]", "r2");

		MockHttpServletResponse response = new MockHttpServletResponse();

		sheetController.handleRequest(request, response);

		assertEquals(0, sheetManager.get(unauthorizedSheet.getId())
				.getAnswerList().size());
	}

	@Test
	public void testNonLoggedUserSubmitOnUnvailableSheet() throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("POST",
				"sheet.htm");

		request.setParameter("id", String.valueOf(unauthorizedSheet.getId()));
		request.setParameter("answers[1]", "r1");
		request.setParameter("answers[2]", "r2");

		MockHttpServletResponse response = new MockHttpServletResponse();

		sheetController.handleRequest(request, response);

		assertEquals(0, sheetManager.get(unauthorizedSheet.getId())
				.getAnswerList().size());
	}

	@Test
	public void testLoggedUserSubmitOnAvailableSheetAndForgetObligatoryQuestion()
			throws Exception {
		MockHttpServletRequest request = new MockHttpServletRequest("POST",
				"sheet.htm");

		request.getSession().setAttribute("user", simpleUser);
		request.setParameter("id", String.valueOf(sheet.getId()));

		MockHttpServletResponse response = new MockHttpServletResponse();

		ModelAndView mav = sheetController.handleRequest(request, response);
		SheetForm form = (SheetForm) request.getAttribute("command");
		assertNotNull(form);

		// / bizarrement y'a pas de validation automatique quand on appelle
		// directement handleRequest

		assertFalse(validateForm(form));
		// assertEquals(0,
		// sheetManager.get(sheet.getId()).getAnswerList().size());
	}

}